package com.crawler.waf.exceptions.handlers;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import com.crawler.waf.exceptions.extendExceptions.CustomExceptionSupport;
import com.crawler.waf.exceptions.extendExceptions.WafExceptionSupport;
import com.crawler.waf.exceptions.providers.ErrorMessageProvider;
import com.crawler.waf.exceptions.providers.WafDefaultErrorMessageProvider;


/**
 * 默认实现 {@link WafExceptionHandler} 接口.<br>
 * 一个异常捕获器的产生，在web项目中，主要有以下几种产生的状态。<br>
 * 1、与异常类对应，产生对应的捕获器。根据异常的不同，有可能会指定特定的异常支持类<br>
 * 2、与响应码对应，产生对应的捕获器。
 * 3、同时指定异常和响应码的时候，指定特定的捕获器进行处理
 */
public abstract class AbstractWafExceptionHandler implements WafExceptionHandler {

	private static final Logger LOG = LoggerFactory.getLogger(WafExceptionHandler.class);

	private  Class<?> exceptionClass = null;
	private  HttpStatus status;
	private ErrorMessageProvider provider = new WafDefaultErrorMessageProvider();

	/**
	 * 
	 * 将http的响应码作为code实现，并且干呢局status获取异常类
	 * @param status
	 *            HTTP status
	 */
	protected AbstractWafExceptionHandler(HttpStatus status) {
		this.status = status;
	}
	/**
	 * 通过异常类型构建一个Handler
	 * @param exceptionClass
	 */
	protected AbstractWafExceptionHandler(Class<?> exceptionClass) {
		this.exceptionClass = exceptionClass;
	}

	/**
	 * 通过状态码和异常消息的支持类构建Hanler
	 * @param status
	 * @param provider
	 */
	protected AbstractWafExceptionHandler(HttpStatus status,ErrorMessageProvider provider) {
		this.provider = provider;
		this.status = status;
	}
	/**
	 * 通过异常类和状态码以及异常消息的支持类构建一个handler
	 * @param exceptionClass
	 * @param status
	 * @param provider
	 */
	protected AbstractWafExceptionHandler(Class<?> exceptionClass,
			HttpStatus status,ErrorMessageProvider provider) {
		this.exceptionClass = exceptionClass;
		this.status = status;
		this.provider = provider;
	}
	/**
	 * 通过异常类和响应码构建handler
	 * @param exceptionClass
	 * @param status
	 */
	protected AbstractWafExceptionHandler(Class<?> exceptionClass,
			HttpStatus status) {
		this.exceptionClass = exceptionClass;
		this.status = status;
	}

	public abstract Object createBody(Exception ex, HttpServletRequest req);

	@Override
	public ResponseEntity<?> handleException(Exception ex, HttpServletRequest req) {
		if(WafExceptionSupport.class.isInstance(ex)){
			this.status = ((WafExceptionSupport)ex).getStatus();
		}
		
		logException(ex, req);
		
		Object body = createBody(ex, req);
		HttpHeaders headers = createHeaders(ex, req);
		
		return new ResponseEntity<>(body, headers, getStatus());
	}
	
	
	public Class<?> getExceptionClass() {
		return exceptionClass;
	}

	public HttpStatus getStatus() {
		if(this.status==null){
			status = HttpStatus.INTERNAL_SERVER_ERROR;
		}
		return status;
	}

	protected HttpHeaders createHeaders(Exception ex, HttpServletRequest req) {
		return new HttpHeaders();
	}

	/**
	 * 将异常信息写入日志系统的具体实现
	 *
	 * @param ex
	 *            The exception to log.
	 * @param req
	 *            The current web request.
	 */
	protected void logException(Exception ex, HttpServletRequest req) {

		if (LOG.isErrorEnabled() && getStatus().value() >= 500
				|| LOG.isInfoEnabled()) {
			Marker marker = MarkerFactory.getMarker(ex.getClass().getName());

			String uri = req.getRequestURI();
			if (req.getQueryString() != null) {
				uri += '?' + req.getQueryString();
			}
			String msg = String.format("%s %s ~> %s", req.getMethod(), uri,
					getStatus());

			if (getStatus().value() >= 500) {
				if(ex instanceof CustomExceptionSupport){
					LOG.error(marker, msg  + "\n" + ex.getMessage());
				}
				else{					
					LOG.error(marker, msg, ex);
				}

			} else if (LOG.isDebugEnabled()) {
				LOG.debug(marker, msg, ex);

			} else {
				LOG.info(marker, msg);
			}
		}
	}

	public ErrorMessageProvider getProvider() {
		return provider;
	}
	
}
